import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

public class Boing extends JPanel implements KeyListener, MouseListener,
		MouseMotionListener, Runnable {
	private Lopta[] lopte = new Lopta[15];
	private Color[] boje = { Color.yellow, Color.white, Color.gray, Color.red,
			Color.orange, Color.green, Color.blue };
	private Color bojaPozadine = new Color(10, 10, 10);
	private Rectangle pozadina;
	private boolean init = false;
	private Rectangle r = new Rectangle(0, 0, 800, 600);
	private Dimension d = new Dimension();
	private float interval = 0.2f;
	private double g = 9.81;
	private int x1, y1;
	private AffineTransform jedinicnaAF = new AffineTransform();
	private BasicStroke okvirCrtanje = new BasicStroke(3);
	private Line2D donja = new Line2D.Double();
	private Line2D leva = new Line2D.Double();
	private Line2D desna = new Line2D.Double();

	// za iscrtavanje senke linije koja ogranicava kretanje lopti
	private boolean desioPritisak,crtajSenku;
	private Line2D senka = new Line2D.Double();
	private int xpocetak, ypocetak, xkraj, ykraj;

	public Boing() {
		addMouseListener(this);
		addMouseMotionListener(this);

	}

	public void init() {
		if (!init) {
			d = getSize();
			pozadina = new Rectangle(d.width, d.height);
			r = new Rectangle(0, 0, (int) d.getWidth(), (int) d.getHeight());
			for (int i = 0; i < lopte.length; i++) {
				Vektor pozicija = new Vektor(2 * d.getWidth() / 3
						- d.getWidth() / 3 * Math.random(), 2 * d.getHeight()
						/ 3 - d.getHeight() / 3 * Math.random());
				Vektor brzina = new Vektor(Math.random() * 20 - 10,
						Math.random() * 6 - 3);

				int colorIndex1 = (int) (Math.random() * boje.length);
				int colorIndex2 = (int) (Math.random() * boje.length);

				lopte[i] = new Lopta(pozicija, brzina,
						(float) (Math.random() * 40 + 10), boje[colorIndex1],
						boje[colorIndex2]);
			}

			init = true;
		}
	}

	public void paint(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		Paint p = g2d.getPaint();
		Stroke b = g2d.getStroke();

		d = getSize();
		Image ii = createImage(d.width, d.height);
		Graphics2D goff = (Graphics2D) ii.getGraphics();

		goff.setPaint(bojaPozadine);
		pozadina.setSize(d.width, d.height);
		goff.fill(pozadina);

		for (int i = 0; i < lopte.length; i++)
			if (lopte[i] != null)
				lopte[i].crtaj(goff);

		jedinicnaAF.setToIdentity();
		goff.setTransform(jedinicnaAF);// neutralna
		goff.setStroke(okvirCrtanje);
		goff.setPaint(Color.red);
		leva.setLine(r.getX(), r.getY(), r.getX(), r.getY() + r.getHeight());
		goff.draw(leva);
		donja.setLine(r.getX(), r.getY() + r.getHeight(),
				r.getX() + r.getWidth(), r.getY() + r.getHeight());
		goff.draw(donja);
		desna.setLine(r.getX() + r.getWidth(), r.getY(),
				r.getX() + r.getWidth(), r.getY() + r.getHeight());
		goff.draw(desna);

		// crtanje senke ako je u procesu crtanja
		if (crtajSenku) {
			goff.setPaint(Color.gray);
			senka.setLine(xpocetak, ypocetak, xkraj, ykraj);
			goff.draw(senka);
		}

		g2d.drawImage(ii, 0, 0, this);

		g2d.setPaint(p);
		g2d.setStroke(b);
	}

	// KeyListener implementation
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			g += 0.5;
			break;
		case KeyEvent.VK_DOWN:
			if (g > 0.5)
				g -= 0.5;
			break;

		case KeyEvent.VK_LEFT:
			interval -= 0.01f;
			if (interval < 0.01f)
				interval = 0.01f;
			break;

		case KeyEvent.VK_RIGHT:
			interval += 0.01f;
			break;
		}
	}

	public void keyReleased(KeyEvent e) {
	}

	public void keyTyped(KeyEvent e) {
	}

	// MouseListener implementation
	public void mouseClicked(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
		int x = x1 > e.getX() ? e.getX() : x1;
		int y = y1 > e.getY() ? e.getY() : y1;
		int w = Math.abs(x1 - e.getX());
		int h = Math.abs(y1 - e.getY());

		// r = new Rectangle(x, y, w, h);
		r.setRect(x, y, w, h);
		crtajSenku = false;
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
		x1 = e.getX();
		y1 = e.getY();
		desioPritisak = true;
		xpocetak = e.getX();
		ypocetak = e.getY();
	}

	public void mouseEntered(MouseEvent e) {
	}

	private void pomeriLopte() {
		for (int j = 0; j < lopte.length; j++) {
			lopte[j].pomeri(interval, g, r);
		}
	}

	public void run() {
		long starttime;

		init();

		while (true) {
			starttime = System.currentTimeMillis();
			try {
				repaint();
				pomeriLopte();
				starttime += 40;
				Thread.sleep(Math.max(0, starttime - System.currentTimeMillis()));
			} catch (InterruptedException e) {
				break;
			}
		}
	}

	public static void main(String s[]) {
		Boing panel = new Boing();

		panel.setOpaque(true);

		JFrame frame = new JFrame("Boing");
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		frame.getContentPane().add(panel);
		frame.setSize(new Dimension(800, 600));
		frame.setVisible(true);
		frame.addKeyListener(panel);

		Thread t = new Thread(panel);
		t.start();
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub
		xkraj = e.getX();
		ykraj = e.getY();
		if(desioPritisak){
			crtajSenku=true;
			desioPritisak=false;
		}

	}

	@Override
	public void mouseMoved(MouseEvent e) {

	}
}